package com.yunbiao.ybbusstopplate.serialport.agreement;

import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.LogUtils;
import com.yunbiao.ybbusstopplate.bean.SiteInfoBean;
import com.yunbiao.ybbusstopplate.utils.BytesUtils;
import com.yunbiao.ybbusstopplate.utils.StringUtils;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import tp.xmaihh.serialport.SerialHelper;

public class LTYPortAgreement extends BaseAgreement{

    private static final class Holder{
        public static final LTYPortAgreement INSTANCE = new LTYPortAgreement();
    }

    public static LTYPortAgreement getInstance(){
        return Holder.INSTANCE;
    }

    private LTYPortAgreement(){
        bytesList = new ArrayList<>();
    }

    @Override
    public void setAgreementListener(IAgreementListener agreementListener) {
        super.setAgreementListener(agreementListener);
    }

    private Disposable disposable;
    private final List<Byte> bytesList;
    private final StringBuilder stringBuilder = new StringBuilder();
    public void anlzData(@Nullable SerialHelper serialHelper, @NotNull byte[] bytes) {
        if(bytes.length == 0){
            return;
        }

        if(bytes.length >= 5){
            byte order = bytes[2];
            //如果是进出站则直接处理
            if(order == 0x11 || order == 0x12){
                Log.d(TAG, "进出站指令：直接处理");
                byte lengthHigh = bytes[3];
                byte lengthLow = bytes[4];
                bytes[3] = lengthLow;
                bytes[4] = lengthHigh;

                checkData(bytes);
                return;
            }
        }

        /*
         * 此报站器在发送站点列表时会分多条发送，后续指令没有附带指令头和指令尾，
         * 而且和线路信息一起发时会导致拼接，出现两组数据头或两条指令拼一起的情况，如[55b51355b510XXXXXX55b513XXXXX]
         * 所以要接收到最后一条指令的三秒后再处理，确保数据完整
         */
        String hex = BytesUtils.bytesToHex(bytes);
        Log.d(TAG, "添加：" + hex);
        stringBuilder.append(hex);

        if(disposable != null && !disposable.isDisposed()){
            disposable.dispose();
            disposable = null;
        }
        disposable = Observable.timer(3, TimeUnit.SECONDS)
                .subscribe(aLong -> {
                    String hexString = stringBuilder.toString();
                    Log.e(TAG, "数据集: " + stringBuilder.toString());
                    stringBuilder.setLength(0);

                    String[] split = hexString.split("55b5");
                    for (String str : split) {
                        if(TextUtils.isEmpty(str)){
                            Log.e(TAG, "空指令");
                            continue;
                        }
                        if(str.length() < 5){
                            Log.e(TAG, "无效指令");
                            continue;
                        }
                        //在每条指令前面补一组指令头，形成完整的指令
                        String h = "55b5" + str;
                        Log.e(TAG, "指令：" + h);

                        //排除重复的数据头，保留后面的一个
//                        if(h.startsWith("55b51355b510")){
//                            h = h.replace("55b513","");
//                        }

                        byte[] data = BytesUtils.hexToByteArray(h);
                        byte start = data[0];//起始
                        byte id = data[1];//ID号
                        byte order = data[2];//命令字

                        byte lengthHigh = data[3];
                        byte lengthLow = data[4];
                        data[3] = lengthLow;
                        data[4] = lengthHigh;

                        byte[] lengthByte = new byte[]{data[3],data[4]};
                        int lengthInt = BytesUtils.hex16to10(BytesUtils.bytesToHex(lengthByte));
                        if(lengthInt + 1 + 1 + 1 + 2 + 1 != data.length){
                            Log.e(TAG, "长度不正确：" + data.length + "!=" + lengthInt);
                        }

                        String s = BytesUtils.bytesToHex(data);
                        Log.d(TAG, "发送后：" + s);
                        checkData(data);

                        Log.e(TAG, " ------------------------------------------------------------ ");
                    }
                });
    }

    private void checkData(byte[] bytes){
        try {
            if(bytes.length == 0){
                d("数据为空");
                return;
            }

            if(bytes.length < 5){
                d("数据<5字节");
                for (byte b : bytes) {
                    bytesList.add(b);
                }
                return;
            }
            for (byte aByte : bytes) {
                bytesList.add(aByte);
            }

            //组合数据
            byte[] data = new byte[bytesList.size()];
            for (int i = 0; i < data.length; i++) {
                data[i] = bytesList.get(i);
            }
            bytesList.clear();

            byte startByte = data[0];
            if(startByte != (byte)0x55){
                d("起始字节校验失败：" + BytesUtils.byteToHex(startByte));
                return;
            }

            byte idByte = data[1];
            if(idByte != (byte)0xB5){
                d("ID号校验失败：" + BytesUtils.byteToHex(idByte));
                return;
            }

            byte commandByte = data[2];
            d("命令字节：" + BytesUtils.byteToHex(commandByte));

            byte[] lengthBytes = BytesUtils.SubByte(data, 3, 2);
            String lengthHex = BytesUtils.bytesToHex(lengthBytes);
            int lengthInt = BytesUtils.hex16to10(lengthHex);
            d("数据长度：" + lengthInt);

            byte[] dataBytes = BytesUtils.SubByte(data, 5, lengthInt);

            String s = BytesUtils.bytesToHex(dataBytes);
            d("截取后的数据：" + s);

            switch (commandByte) {
                case (byte)0x10://站点列表
                    siteList(dataBytes);
                    break;
                case (byte)0x11://进站
                    inSite(dataBytes);
                    break;
                case (byte)0x12://出战
                    outSite(dataBytes);
                    break;
                case (byte)0x13://线路信息
                    lineInfo(dataBytes);
                    break;
            }
        } catch (Exception e){
            e(e);
        }
    }

    /**
     * 线路信息
     * @param dataBytes
     */
    private void lineInfo(byte[] dataBytes){
        String lineInfoHex = BytesUtils.bytesToHex(dataBytes);
        d("线路信息HEX：" + lineInfoHex);
        String lineInfoString = StringUtils.hexStringToString(lineInfoHex,"GBK");
        d("线路信息：" + lineInfoString);

        String startStation = lineInfoString.substring(0,lineInfoString.indexOf("["));
        String lineName = lineInfoString.substring(lineInfoString.indexOf("[") + 1, lineInfoString.indexOf("]"));
        String endStation = lineInfoString.substring(lineInfoString.indexOf("]") + 1);
        d("起点站：" + startStation + "，线路名：" + lineName + "，终点站：" + endStation);

        if(lineName.contains("路")){
            lineName = lineName.replace("路","");
        }

        if (agreementListener != null) {
            agreementListener.onLineInfoResult(new String[]{lineName,startStation,endStation});
        }
    }

    /**
     * 进站
     * @param dataBytes
     */
    private void inSite(byte[] dataBytes){
        byte upDownByte = dataBytes[0];

        byte siteNumByte = dataBytes[1];
        String siteNumHex = BytesUtils.byteToHex(siteNumByte);
        int siteNumInt = BytesUtils.hex16to10(siteNumHex);

        d("进站：" + siteNumInt + " ---" + (upDownByte == 0x00 ? "上行" : "下行"));

        SiteInfoBean siteInfoBean = new SiteInfoBean();
        siteInfoBean.setStutas(1);
        siteInfoBean.setIndex(siteNumInt);
        if (agreementListener != null) {
            agreementListener.onSiteTipResult(siteInfoBean);
        }
    }

    /**
     * 出站
     * @param dataBytes
     */
    private void outSite(byte[] dataBytes){
        byte upDownByte = dataBytes[0];

        byte siteNumByte = dataBytes[1];
        String siteNumHex = BytesUtils.byteToHex(siteNumByte);
        int siteNumInt = BytesUtils.hex16to10(siteNumHex);

        d( "出站：" + siteNumInt + " ---" + (upDownByte == 0x00 ? "上行" : "下行"));

        SiteInfoBean siteInfoBean = new SiteInfoBean();
        siteInfoBean.setStutas(0);
        siteInfoBean.setIndex(siteNumInt + 1);
        if (agreementListener != null) {
            agreementListener.onSiteTipResult(siteInfoBean);
        }
    }

    /**
     * 站点列表
     */
    ArrayList<String> siteList = new ArrayList<>();
    private void siteList(byte[] dataBytes){
        siteList.clear();

        Queue<Byte> byteQueue = new LinkedList<>();
        for (byte dataByte : dataBytes) {
            byteQueue.add(dataByte);
        }

        Byte upDownByte = byteQueue.poll();

        Byte siteCountByte = byteQueue.poll();
        String siteCountHex = BytesUtils.byteToHex(siteCountByte);
        int siteCountInt = BytesUtils.hex16to10(siteCountHex);
        d("上下行：" + (upDownByte == 0x00 ? "上行" : "下行") + " --- 总站点数：" + siteCountInt);

        int flag = 0;
        int length = 0;
        while (!byteQueue.isEmpty()) {
            switch (flag) {
                case 0:
                    flag = 1;
                    Byte siteIndex = byteQueue.poll();
                    break;
                case 1:
                    flag = 2;
                    Byte siteNameLengthByte = byteQueue.poll();
                    String siteNameLengthHex = BytesUtils.byteToHex(siteNameLengthByte);
                    length = BytesUtils.hex16to10(siteNameLengthHex);
                    break;
                case 2:
                    flag = 0;
                    if(length > 0){
                        byte[] siteNameBytes = new byte[length];
                        for (int i = 0; i < siteNameBytes.length; i++) {
                            siteNameBytes[i] = byteQueue.poll();
                        }
                        String siteNameHex = BytesUtils.bytesToHex(siteNameBytes);
                        String siteNameString = StringUtils.hexStringToString(siteNameHex,"GBK");
                        siteList.add(siteNameString);
                    }
                    break;
            }
        }

        d(siteList.toString());

        if (agreementListener != null) {
            agreementListener.onSiteListResult(siteList);
        }
    }

    private static final String TAG = "LTYPortAgreement";
    private void d(String log){
        LogUtils.dTag(TAG,log);
//        Log.d(TAG, log);
    }
    private void e(Throwable t){
//        Log.e(TAG, (t == null ? "NULL" : t.getMessage()) );
        LogUtils.eTag(TAG,t);
    }


















    // 55
    // B5
    // 13
    // 001a
    // e8b5b7e782b9e7ab995b333333e8b7af5de7bb88e782b9e7ab99
    // FF
    public void testLineInfo(String upDownHex){
        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder
                .append("55")//起始位
                .append("B5")//ID号
                .append("13");//命令字

        //线路信息
        String lineInfoString;
        if(TextUtils.equals("00",upDownHex)){
            lineInfoString = "起点站[333路]终点站";
        } else {
            lineInfoString = "终点站[333路]起点站";
        }
        //线路信息HEX
        String lineInfoHex = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            lineInfoHex = BytesUtils.bytesToHex(lineInfoString.getBytes(StandardCharsets.UTF_8));
        }
        //数据长度
        int lineInfoLengthInt = lineInfoHex.length() / 2;
        String lineInfoLengthHex = Integer.toHexString(lineInfoLengthInt);
        lineInfoLengthHex = addZero(lineInfoLengthHex,4);

        stringBuilder.append(lineInfoLengthHex).append(lineInfoHex).append("FF");
        byte[] bytes = BytesUtils.hexToByteArray(stringBuilder.toString());

        Log.d(TAG, "testLineInfo: " + stringBuilder.toString());
        anlzData(null,bytes);
    }

    int inOut = 0;
    int index = 0;
    int upDown = 0;
    public void testSite(){
//        if(inOut == 0){
//            inOut = 1;
//            testInSite();
//        } else if(inOut == 1){
//            inOut = 0;
//            testOutSite();
//        }

        String s = "55b51102000101f3";
        byte[] bytes = BytesUtils.hexToByteArray(s);
        anlzData(null,bytes);
    }

    private void testInSite(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("55").append("B5").append("11");
        //上下行
        StringBuilder dataBuilder = new StringBuilder();
        String upDownHex = Integer.toHexString(upDown);
        upDownHex = addZero(upDownHex,2);
        dataBuilder.append(upDownHex);
        //站点序号
        String indexHex = Integer.toHexString(index);
        indexHex = addZero(indexHex,2);
        dataBuilder.append(indexHex);
        //数据长度
        int dataLengthInt = dataBuilder.length() / 2;
        String dataLengthHex = Integer.toHexString(dataLengthInt);
        dataLengthHex = addZero(dataLengthHex,4);

        stringBuilder.append(dataLengthHex).append(dataBuilder).append("FF");
        Log.d(TAG, "进站：" + stringBuilder);

        byte[] bytes = BytesUtils.hexToByteArray(stringBuilder.toString());
        anlzData(null,bytes);
    }

    private void testOutSite(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("55").append("B5").append("12");

        StringBuilder dataBuilder = new StringBuilder();
        String upDownHex = Integer.toHexString(upDown);
        upDownHex = addZero(upDownHex,2);
        dataBuilder.append(upDownHex);

        String indexHex = Integer.toHexString(index);
        indexHex = addZero(indexHex,2);
        dataBuilder.append(indexHex);

        int dataLengthInt = dataBuilder.length() / 2;
        String dataLengthHex = Integer.toHexString(dataLengthInt);
        dataLengthHex = addZero(dataLengthHex,4);

        stringBuilder.append(dataLengthHex).append(dataBuilder).append("FF");
        Log.d(TAG, "出站：" + stringBuilder);

        index ++;
        if(index >=  siteList.size()){
            index = 0;
        }

        byte[] bytes = BytesUtils.hexToByteArray(stringBuilder.toString());
        anlzData(null,bytes);
    }

    public void testSiteList(String upDownHex){
//        List<String> originList = new ArrayList<>();
//        for (int i = 0; i < 30; i++) {
//            originList.add("站点" + i);
//        }
//
//        if(TextUtils.equals("00",upDownHex) && upDown != 0){
//            upDown = 0;
//            index = 0;
//        } else if(TextUtils.equals("01",upDownHex) && upDown != 1){
//            upDown = 1;
//            index = 0;
//        }
//
//        StringBuilder stringBuilder = new StringBuilder();
//
//        stringBuilder
//                .append("55")//起始位
//                .append("B5")//ID号
//                .append("10");//命令字
//        //总站点数
//        String siteCountHex = Integer.toHexString(originList.size());
//        siteCountHex = addZero(siteCountHex,2);
//
//        StringBuilder dataBuilder = new StringBuilder();
//        dataBuilder
//                .append(upDownHex)//上下行
//                .append(siteCountHex);//总站数
//
//        //站点数据
//        for (int i = 0; i < originList.size(); i++) {
//            int index;
//            if(TextUtils.equals("00",upDownHex)){
//                index = i;
//            } else {
//                index = originList.size() - i - 1;
//            }
//            //站点序号
//            String siteIndex = Integer.toHexString(index);
//            siteIndex = addZero(siteIndex,2);
//            //站点名称
//            String siteName = originList.get(index);
//            String siteNameHex = null;
//            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
//                siteNameHex = BytesUtils.bytesToHex(siteName.getBytes(StandardCharsets.UTF_8));
//            }
//            //站名长度
//            int siteNameLength = siteNameHex.length() / 2;
//            String siteNameLengthHex = Integer.toHexString(siteNameLength);
//            siteNameLengthHex = addZero(siteNameLengthHex,2);
//
//            dataBuilder
//                    .append(siteIndex)//站点序号
//                    .append(siteNameLengthHex)//站名长度
//                    .append(siteNameHex);//站名
//        }
//
//
//        //数据长度
//        int dataLength = dataBuilder.length() / 2;
//        String dataLengthHex = Integer.toHexString(dataLength);
//        dataLengthHex = addZero(dataLengthHex,4);
//
//        stringBuilder
//                .append(dataLengthHex)//数据长度
//                .append(dataBuilder)//数据位
//                .append("FF");//校验位
//        Log.d(TAG, stringBuilder.toString());
//
//        byte[] bytes = BytesUtils.hexToByteArray(stringBuilder.toString().toUpperCase());
//        anlzData(null,bytes);

        new Thread(() -> {
            fileNameIndex += 1;

            File dir = new File(Environment.getExternalStorageDirectory(),"LTY");
            File file = new File(dir,fileNameIndex + ".txt");
            List<byte[]> orderList = readFile(file);
            for (byte[] bytes : orderList) {
                anlzData(null,bytes);
            }
        }).start();
    }
    private int fileNameIndex = 0;


    private List<byte[]> readFile(File file){
        List<byte[]> stringList = new ArrayList<>();
        List<String> strings = FileIOUtils.readFile2List(file);
        Log.d(TAG, "读取文件：" + file.getPath());
        if(strings != null && !strings.isEmpty()){
            for (String string : strings) {
                if(TextUtils.isEmpty(string)){
                    continue;
                }
                if(string.contains("<-----")){
                    continue;
                }
                if(string.contains("<---")){
                    int i = string.lastIndexOf("-");
                    String substring = string.substring(i + 1);
                    byte[] bytes = BytesUtils.hexToByteArray(substring);
                    stringList.add(bytes);
                }
            }
        }
        return stringList;
    }

    private String addZero(String hex,int len){
        String hexData = hex;
        while (hexData.length() < len) {
            hexData = "0" + hexData;
        }
        return hexData;
    }
}
